package com.obrock;

import java.text.NumberFormat;
import java.text.ParseException;

/**
 * Created with IntelliJ IDEA.
 * User: Дмитрий Г. Кузнецов
 * Date: 10.10.12
 * Time: 16:45
 * To change this template use File | Settings | File Templates.
 */
public class Eval {

    String src_query = "";

    public Eval(String s) {
        src_query = s;
    }


    boolean is_op(String c) {
        switch (c.charAt(0)) {
            case '+':
            case '-':
            case '/':
            case '*':
            case '(':
            case ')':
            case '%':
            case ';':
                return true;
        }
        return false;
    }

    String cat(String dst, String src) {
        if (src.charAt(0) != '(') {
            dst = dst.concat(src);
            dst = dst.concat(";");
        }
        return dst;
    }

    int level(String op) {
        switch (op.charAt(0)) {
            case '+':
            case '-':
                return 1;
            case '/':
            case '*':
            case '%':
                return 2;
            //case L'(':
            //	return 3;
        }
        return 3;
    }

    String get_token(String src) {
        String dst = "";

        if (src.length() == 0) return null;
        if (is_op(src)) {
            dst = src.substring(0, 1);
        } else {
            while (src.length() > 0 && !is_op(src)) {
                if (src.charAt(0) == ' ' || src.charAt(0) == '\t') {
                    src = src.substring(1);
                    continue;
                }
                dst += src.substring(0, 1);
                src = src.substring(1);
            }
        }
        return dst;
    }

    String cutz(String str) {
        String tmp = "";
        for (int i = 0; i < str.length(); ++i) {
            switch (str.charAt(i)) {
                case ' ':
                case '\t':
                case '\r':
                case '\n':
                case ';':
                    break;
                default:
                    tmp += str.substring(i, i + 1);
            }
        }
        return tmp;
    }

    String eval_rpn(String src_query) {
        String[] stack = new String[256];
        int m = 0;
        String token = "";
        String result = "";
        String query = cutz(src_query);
        String ch = "";

        while ((ch = get_token(query)) != null) {
            token = ch;
            query = query.substring(ch.length());

            if (!is_op(token)) {
                result = cat(result, token);
            } else if (token.charAt(0) == '(') {
                stack[m++] = token;
            } else if (token.charAt(0) == ')') {
                while (m > 0 && (ch = stack[--m]).charAt(0) != '(') {
                    result = cat(result, ch);
                }
            } else {
                while (m > 0 && (ch = stack[m - 1]).charAt(0) != '(' && level(token) < level(stack[m - 1])) {
                    result = cat(result, stack[--m]);
                }
                stack[m++] = token;
            }
        }
        while (m > 0) {
            result = cat(result, stack[--m]);
        }
        return result;
    }

    double evaluate() {
        double[] stack = new double[256];
        double result = 0;
        double temp = 0;
        int m = 0;

        String src = eval_rpn(src_query);

        String ch;
        while ((ch = get_token(src)) != null) {
            src = src.substring(ch.length());
            switch (ch.charAt(0)) {
                case ';':
                    break;
                case '+':
                    result += stack[--m];
                    break;
                case '-':
                    result = stack[--m] - result;
                    break;
                case '*':
                    result *= stack[--m];
                    break;
                case '/':
                    result = stack[--m] / result;
                    break;
                case '%':
                    result = stack[m - 1] * result / 100.0;
                    break;
                default:
                    stack[m++] = result;
                    result = Double.parseDouble(ch.replace(" ", "").replace(",", "."));

            }
        }
        return result;
    }
}
